//binder.cc
#include "binder.h"
#include "syscall2.h"
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include "network.h"
#include "post.h"
#include "interrupt.h"
#include "system.h"

void BinderMain()
{
	printf("INITIALIZING BINDER...\n");
	
	PacketHeader inPktHdr;
	MailHeader inMailHdr;
	char *buf = new char[MaxMailSize];
	std::vector<int> servers;
	
	srand( time(NULL) );
	
	printf("BINDER RUNNING!\n");
	
	while(true)
	{
		postOffice->Receive(0, &inPktHdr, &inMailHdr, buf);
		//printf("Binder received a message!\n");
		
		char* msgID = new char;
		memcpy(msgID, buf, 1);
		
		switch(*msgID)
		{
			case BIND_Add:
			{
				printf("Binder received registration message!\n");
				int serverToAdd = (int)inPktHdr.from;
				if(servers.size() < MAX_SERVERS)
				{
					servers.push_back(serverToAdd);
					printf("Binder registered Server ID %d!\n", serverToAdd);
				}else{
					printf("ERROR: Server list full! Binder cannot register Server ID %d!\n", serverToAdd);
				}
				break;
			}
			
			case BIND_Remove:
			{
				printf("Binder received deregistration message!\n");
				int serverToRemove = -1;
				int indexToRemove = -1;
				memcpy(&serverToRemove, buf, 8);
				
				for(int i = 0; i < servers.size(); i++)
				{
					if(servers[i] == serverToRemove)
					{
						indexToRemove = i;
						break;
					}
				}
				
				if(indexToRemove == -1)
				{
					printf("Error: Server %d never registered!\n", serverToRemove);
				}else{
					servers.erase(servers.begin() + indexToRemove);
					printf("Binder deregistered Server ID %d!\n", serverToRemove);
				}
				
				break;
			}
			
			case BIND_List:
			{
				printf("Binder received List message!\n");
			
				char* outbuf = new char[MaxMailSize];
				if (!outbuf)
				{	
					printf("%s","List response buffer couldn't be created for some reason\n");
					return;
				}
				
				char scName = BIND_List;
				int count = servers.size();
				memcpy(outbuf, &scName, 1);
				memcpy(outbuf+1, &count, 8);
				
				//populate list
				char serverChar = 0;
				for(int i = 0; i < count; i++)
				{
					int serverInt = servers[i];
					serverChar = serverInt;
					memcpy(outbuf+9+i, &serverChar, 1);	
				}
				
				//Create and send mail
				PacketHeader outPktHdr;
				MailHeader outMailHdr;
				
				outPktHdr.to = inPktHdr.from;
				outMailHdr.to = inMailHdr.from;
				outMailHdr.from = 0;
				outMailHdr.length = MaxMailSize;
				
				bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
				if ( !success ) {
				  printf("The postOffice Send for BIND_List failed. You must not have the other Nachos running.\n");
				}
				break;
			}
			
			case BIND_Rand:
			{
				printf("Binder received Rand message!\n");
				int serverIndex = (int)( rand() % servers.size() );
				int serverID = servers[serverIndex];
				
				char* outbuf = new char[MaxMailSize];
				if (!outbuf)
				{	
					printf("%s","Random response buffer couldn't be created for some reason\n");
					return;
				}
				
				char scName = BIND_Rand;
				memcpy(outbuf, &scName, 1);
				memcpy(outbuf+1, &serverID, 8);
				
				//Create and send mail
				PacketHeader outPktHdr;
				MailHeader outMailHdr;
				
				outPktHdr.to = inPktHdr.from;
				outMailHdr.to = inMailHdr.from;
				outMailHdr.from = 0;
				outMailHdr.length = MaxMailSize;
				
				bool success = postOffice->Send(outPktHdr, outMailHdr, outbuf); 
				if ( !success ) {
				  printf("The postOffice Send for BIND_Rand failed. You must not have the other Nachos running.\n");
				}
			
				break;
			}
			default:
			{
				int msg = (int) *msgID;
				printf("Binder received unknown message type '%d'\n",msg);
			}
		}
		
	}
}
